package com.luanye.enjoy.controller;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.luanye.enjoy.dto.*;
import com.luanye.enjoy.vo.RespBean;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static com.luanye.enjoy.constants.Const.POST_TAG;
import static com.luanye.enjoy.constants.Const.PRE_TAG;

@RestController
@AllArgsConstructor
@RequestMapping("/search")
@Slf4j
public class SearchController {

    private final ElasticsearchRestTemplate elasticsearchRestTemplate;

    @PutMapping("/baike")
    public RespBean search1(@RequestBody PolicySearch condition){
        return RespBean.success(searchBaiKe(buildBaiKeQuery(condition.getKeyword())));
    }

    @PutMapping("/dynamic")
    public RespBean search2(@RequestBody PolicySearch condition){
        return RespBean.success(searchDynamic(buildDynamicQuery(condition.getKeyword())));
    }


    @PutMapping("/wiki")
    public RespBean search3(@RequestBody PolicySearch condition){
        return RespBean.success(searchWiki(buildWikiQuery(condition.getKeyword())));
    }

    @PutMapping("/policy")
    public RespBean search4(@RequestBody PolicySearch condition){
        return RespBean.success(searchPolicy(buildPolicyQuery(condition.getKeyword())));
    }

    @PutMapping("/recipe")
    public RespBean search5(@RequestBody PolicySearch condition){
        return RespBean.success(searchRecipe(buildRecipeQuery(condition.getKeyword())));
    }

    public NativeSearchQueryBuilder buildRecipeQuery(String keywords){
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("recipe_name", keywords))
                        .should(QueryBuilders.matchQuery("steps", keywords)));

        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

    public List<RecipeSearchDTO> searchRecipe(NativeSearchQueryBuilder nativeSearchQueryBuilder){
        HighlightBuilder.Field recipeNameFiled = new HighlightBuilder.Field("recipe_name");
        recipeNameFiled.preTags(PRE_TAG);
        recipeNameFiled.postTags(POST_TAG);

        HighlightBuilder.Field stepsField = new HighlightBuilder.Field("steps");
        stepsField.preTags(PRE_TAG);
        stepsField.postTags(POST_TAG);
        stepsField.fragmentOffset(200);
        nativeSearchQueryBuilder.withHighlightFields(recipeNameFiled, stepsField);

        try{
            SearchHits<RecipeSearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), RecipeSearchDTO.class);
            return search.getSearchHits().stream().map(hit -> {
                RecipeSearchDTO recipe = hit.getContent();
                //获取名称高亮
                List<String> recipe_nameHigh = hit.getHighlightFields().get("recipe_name");
                if (CollectionUtils.isNotEmpty(recipe_nameHigh)){
                    recipe.setRecipe_name(recipe_nameHigh.get(0));
                }
                //获取描述高亮
                List<String> stepHigh = hit.getHighlightFields().get("steps");
                if (CollectionUtils.isNotEmpty(stepHigh)){
                    recipe.setSteps(stepHigh.get(stepHigh.size() - 1));
                }
                return recipe;
            }).collect(Collectors.toList());

        }catch (Exception e){
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    public NativeSearchQueryBuilder buildPolicyQuery(String keywords){
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("title", keywords))
                .should(QueryBuilders.matchQuery("content", keywords))
                .should(QueryBuilders.matchQuery("summery", keywords))
                .should(QueryBuilders.matchQuery("organization_name",keywords))
        );
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

    public List<PolicySearchDTO> searchPolicy(NativeSearchQueryBuilder nativeSearchQueryBuilder){
        HighlightBuilder.Field titleField = new HighlightBuilder.Field("title");
        titleField.preTags(PRE_TAG);
        titleField.postTags(POST_TAG);

        HighlightBuilder.Field contentField = new HighlightBuilder.Field("content");
        contentField.preTags(PRE_TAG);
        contentField.postTags(POST_TAG);

        HighlightBuilder.Field summeryField = new HighlightBuilder.Field("summery");
        summeryField.preTags(PRE_TAG);
        summeryField.postTags(POST_TAG);

        HighlightBuilder.Field organizationField = new HighlightBuilder.Field("organization_name");
        organizationField.preTags(PRE_TAG);
        organizationField.postTags(POST_TAG);

        nativeSearchQueryBuilder.withHighlightFields(titleField, contentField, summeryField, organizationField);

        try{
            SearchHits<PolicySearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), PolicySearchDTO.class);
            return search.getSearchHits().stream().map(hit -> {
                PolicySearchDTO policy = hit.getContent();
                //获取名称高亮
                List<String> titleHigh = hit.getHighlightFields().get("title");
                if (CollectionUtils.isNotEmpty(titleHigh)){
                    policy.setTitle(titleHigh.get(0));
                }
                List<String> contentHigh = hit.getHighlightFields().get("content");
                if (CollectionUtils.isNotEmpty(contentHigh)){
                    policy.setContent(contentHigh.get(0));
                }
                List<String> summeryHigh = hit.getHighlightFields().get("summery");
                if (CollectionUtils.isNotEmpty(summeryHigh)){
                    policy.setSummery(summeryHigh.get(0));
                }
                //获取描述高亮
                List<String> organization_nameHigh = hit.getHighlightFields().get("organization_name");
                if (CollectionUtils.isNotEmpty(organization_nameHigh)){
                    policy.setOrganization_name(organization_nameHigh.get(organization_nameHigh.size() - 1));
                }
                return policy;
            }).collect(Collectors.toList());

        }catch (Exception e){
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    public NativeSearchQueryBuilder buildWikiQuery(String keywords){
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("title", keywords))
                .should(QueryBuilders.matchQuery("context", keywords))
                .should(QueryBuilders.matchQuery("summery", keywords))
                .should(QueryBuilders.matchQuery("organization_name", keywords))
        );
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

    public List<WikiSearchDTO> searchWiki(NativeSearchQueryBuilder nativeSearchQueryBuilder){
        HighlightBuilder.Field titleNameField = new HighlightBuilder.Field("title");
        titleNameField.preTags(PRE_TAG);
        titleNameField.postTags(POST_TAG);

        HighlightBuilder.Field contextNameField = new HighlightBuilder.Field("context");
        contextNameField.preTags(PRE_TAG);
        contextNameField.postTags(POST_TAG);

        HighlightBuilder.Field summeryField = new HighlightBuilder.Field("summery");
        summeryField.preTags(PRE_TAG);
        summeryField.postTags(POST_TAG);

        HighlightBuilder.Field organizationField = new HighlightBuilder.Field("organization_name");
        organizationField.preTags(PRE_TAG);
        organizationField.postTags(POST_TAG);

        nativeSearchQueryBuilder.withHighlightFields(organizationField, titleNameField, contextNameField, summeryField);

        try{
            SearchHits<WikiSearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), WikiSearchDTO.class);
            return search.getSearchHits().stream().map(hit -> {
                WikiSearchDTO wiki = hit.getContent();
                //获取名称高亮
                List<String> titleHigh = hit.getHighlightFields().get("title");
                if (CollectionUtils.isNotEmpty(titleHigh)){
                    wiki.setTitle(titleHigh.get(0));
                }
                //获取描述高亮
                List<String> contextHigh = hit.getHighlightFields().get("context");
                if (CollectionUtils.isNotEmpty(contextHigh)){
                    wiki.setContext(contextHigh.get(contextHigh.size() - 1));
                }
                List<String> summeryHigh = hit.getHighlightFields().get("summery");
                if (CollectionUtils.isNotEmpty(summeryHigh)){
                    wiki.setSummery(summeryHigh.get(0));
                }
                List<String> organizationHigh = hit.getHighlightFields().get("organization_name");
                if (CollectionUtils.isNotEmpty(organizationHigh)){
                    wiki.setOrganization_name(organizationHigh.get(0));
                }
                return wiki;
            }).collect(Collectors.toList());

        }catch (Exception e){
            e.printStackTrace();
        }
        return new ArrayList<>();
    }



    public NativeSearchQueryBuilder buildBaiKeQuery(String keywords){
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("plant_name", keywords))
                .should(QueryBuilders.matchQuery("description", keywords)));
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

    public List<BaiKeSearchDTO> searchBaiKe(NativeSearchQueryBuilder nativeSearchQueryBuilder){
        HighlightBuilder.Field plantNameField = new HighlightBuilder.Field("plant_name");
        plantNameField.preTags(PRE_TAG);
        plantNameField.postTags(POST_TAG);

        HighlightBuilder.Field descriptionField = new HighlightBuilder.Field("description");
        descriptionField.preTags(PRE_TAG);
        descriptionField.postTags(POST_TAG);
        descriptionField.fragmentOffset(200);
        nativeSearchQueryBuilder.withHighlightFields(plantNameField, descriptionField);

        try{
            SearchHits<BaiKeSearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), BaiKeSearchDTO.class);
            return search.getSearchHits().stream().map(hit -> {
                BaiKeSearchDTO baike = hit.getContent();
                //获取名称高亮
                List<String> plantNameHigh = hit.getHighlightFields().get("plant_name");
                if (CollectionUtils.isNotEmpty(plantNameHigh)){
                    baike.setPlant_name(plantNameHigh.get(0));
                }
                //获取描述高亮
                List<String> descriptionHigh = hit.getHighlightFields().get("description");
                if (CollectionUtils.isNotEmpty(descriptionHigh)){
                    baike.setDescription(descriptionHigh.get(descriptionHigh.size() - 1));
                }
                return baike;
            }).collect(Collectors.toList());

        }catch (Exception e){
            e.printStackTrace();
        }
        return new ArrayList<>();
    }

    public NativeSearchQueryBuilder buildDynamicQuery(String keywords){
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery("location", keywords))
                .should(QueryBuilders.matchQuery("content", keywords)));
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        return nativeSearchQueryBuilder;
    }

    public List<DynamicSearchDTO> searchDynamic(NativeSearchQueryBuilder nativeSearchQueryBuilder){
        HighlightBuilder.Field locationFiled = new HighlightBuilder.Field("location");
        locationFiled.preTags(PRE_TAG);
        locationFiled.postTags(POST_TAG);

        HighlightBuilder.Field contentField = new HighlightBuilder.Field("content");
        contentField.preTags(PRE_TAG);
        contentField.postTags(POST_TAG);
        contentField.fragmentOffset(200);
        nativeSearchQueryBuilder.withHighlightFields(locationFiled, contentField);

        try{
            SearchHits<DynamicSearchDTO> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), DynamicSearchDTO.class);
            return search.getSearchHits().stream().map(hit -> {
                DynamicSearchDTO dynamic = hit.getContent();
                //获取名称高亮
                List<String> locationHigh = hit.getHighlightFields().get("location");
                if (CollectionUtils.isNotEmpty(locationHigh)){
                    dynamic.setLocation(locationHigh.get(0));
                }
                //获取描述高亮
                List<String> contentHigh = hit.getHighlightFields().get("content");
                if (CollectionUtils.isNotEmpty(contentHigh)){
                    dynamic.setContent(contentHigh.get(contentHigh.size() - 1));
                }
                return dynamic;
            }).collect(Collectors.toList());

        }catch (Exception e){
            e.printStackTrace();
        }
        return new ArrayList<>();
    }
}
